package com.panda.web.service.order.impl;

import com.panda.web.configuration.WxPayConfig;
import com.panda.web.domain.dto.OrderDTO;
import com.panda.web.entity.order.WechatOrder;
import com.panda.web.mapper.order.WechatOrderMapper;
import com.panda.web.utils.payutils.MiniWxPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class WxRefundService {

    private static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

    @Autowired
    private WxPayConfig wxPayConfig;
    @Autowired
    private WechatOrderMapper orderMapper;

    @Autowired
    private WxPayService wxPayService;
    @Transactional
    public Map<String, String> refund(OrderDTO dto) throws Exception {
        String orderId = dto.getOrderId();
        WechatOrder order = orderMapper.findByOrderId(orderId);

        // 验证订单状态
        validateOrderForRefund(order,dto.getRefundFee());

        // 生成唯一退款单号
        String outRefundNo = generateRefundNo(wxPayConfig.getMchId());

        // 创建退款参数
        Map<String, String> paramMap = createRefundParams(order, outRefundNo,dto.getRefundFee());

        // 签名并转换为XML
        String xmlParam = signAndConvertToXml(paramMap);

        // 执行退款请求
        try (CloseableHttpClient httpClient = createSecureHttpClient()) {
            HttpPost httpPost = new HttpPost(REFUND_URL);
            httpPost.setEntity(new StringEntity(xmlParam, "UTF-8"));
            httpPost.setHeader("Content-Type", "text/xml");

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                String xmlResult = EntityUtils.toString(response.getEntity(), "UTF-8");
                Map<String, String> resultMap = MiniWxPayUtil.xmlToMap(xmlResult);

                // 验证和处理结果
                processRefundResponse(resultMap,outRefundNo);
                return resultMap;
            }
        } catch (Exception e) {
            throw new RuntimeException("退款请求失败", e);
        }
    }

    private void validateOrderForRefund(WechatOrder order, BigDecimal refundFee) {
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }
        if (order.getTransactionId() == null) {
            throw new RuntimeException("订单未支付");
        }
        if ("已退款".equals(order.getRefundStatus())) {
            throw new RuntimeException("该订单已退款，无法重复退款");
        }
        if (refundFee.compareTo(order.getTotalFee())>0) {
            throw new RuntimeException("退款金额超过订单总额");
        }
    }

    private Map<String, String> createRefundParams(WechatOrder order, String outRefundNo, BigDecimal refundFee) {
        Integer price = convertYuanToCentsSafely(refundFee);
        Integer totalFee = convertYuanToCentsSafely(order.getTotalFee());
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", wxPayConfig.getAppId());
        paramMap.put("mch_id", wxPayConfig.getMchId());
        paramMap.put("nonce_str", generateNonceStr());
        paramMap.put("out_trade_no", order.getOrderId());
        paramMap.put("out_refund_no", outRefundNo);

        paramMap.put("total_fee", String.valueOf(totalFee));//总金额
        paramMap.put("refund_fee", String.valueOf(price));
        paramMap.put("notify_url", wxPayConfig.getRefundNotifyUrl());
        paramMap.put("op_user_id", wxPayConfig.getMchId()); // 操作员，默认为商户号

        return paramMap;
    }
    private Integer convertYuanToCentsSafely(BigDecimal yuanAmount) {
        if (yuanAmount == null) {
            throw new IllegalArgumentException("金额不能为空");
        }

        // 将元转分（乘以100）
        BigDecimal cents = yuanAmount.multiply(new BigDecimal(100));

        try {
            // 四舍五入取整
            return cents.setScale(0, RoundingMode.HALF_UP).intValueExact();
        } catch (ArithmeticException e) {
            // 处理金额过大问题
            if (cents.compareTo(BigDecimal.valueOf(Integer.MAX_VALUE)) > 0) {
                throw new IllegalArgumentException("金额过大，超过整数最大值: " + cents);
            } else if (cents.compareTo(BigDecimal.valueOf(Integer.MIN_VALUE)) < 0) {
                throw new IllegalArgumentException("金额不能为负数: " + cents);
            }
            // 对于小数部分无法整除的情况
            throw new IllegalArgumentException("金额包含无法转换的小数部分: " + cents);
        }
    }
    private String signAndConvertToXml(Map<String, String> paramMap) throws Exception {
        // 生成签名
        String sign = generateSignature(paramMap, wxPayConfig.getApiKey());
        paramMap.put("sign", sign);

        // 转换为XML
        return mapToXml(paramMap);
    }

    private CloseableHttpClient createSecureHttpClient() throws Exception {
        // 加载证书
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream inputStream = new FileInputStream(wxPayConfig.getKeyPath())) {
            keyStore.load(inputStream, wxPayConfig.getMchId().toCharArray());
        }

        // 创建 SSLContext
        SSLContext sslContext = createSSLContext(keyStore);

        // 创建 SSLConnectionSocketFactory
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                sslContext,
                new String[]{"TLSv1.2"}, // 支持的协议
                null,                    // 支持的密码套件
                NoopHostnameVerifier.INSTANCE
        );

        // 创建 HTTP 客户端
        return HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .build();
    }

    private SSLContext createSSLContext(KeyStore keyStore) throws Exception {
        // 使用 BouncyCastle 提供者
        Security.addProvider(new BouncyCastleProvider());

        // 创建 SSLContext 实例
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");

        // 初始化 KeyManager
        KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        kmFactory.init(keyStore, wxPayConfig.getMchId().toCharArray());

        // 创建信任所有证书的 TrustManager（仅用于微信支付）
        TrustManager[] trustManagers = {
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
                }
        };

        // 初始化 SSLContext
        sslContext.init(kmFactory.getKeyManagers(), trustManagers, new SecureRandom());
        return sslContext;
    }

    private void processRefundResponse(Map<String, String> resultMap, String outRefundNo) throws Exception {
        if (!"SUCCESS".equals(resultMap.get("return_code"))) {
            throw new RuntimeException("退款请求失败: " + resultMap.get("return_msg"));
        }

        // 验证签名
        if (!verifySignature(resultMap)) {
            throw new RuntimeException("响应签名验证失败");
        }

        if (!"SUCCESS".equals(resultMap.get("result_code"))) {
            throw new RuntimeException("退款失败: " + resultMap.get("err_code_des"));
        }

        // 保存退款记录
//        saveRefundRecord(order, outRefundNo, resultMap);
//
//        // 更新订单状态
//        order.setRefundStatus("处理中");
//        orderMapper.update(order);
    }

//    private boolean verifySignature(Map<String, String> resultMap) throws Exception {
//        String sign = resultMap.get("sign");
//        Map<String, String> signMap = new HashMap<>(resultMap);
//        signMap.remove("sign");
//
//        String calculatedSign = generateSignature(signMap, wxPayConfig.getApiKey());
//        return sign.equals(calculatedSign);
//    }
//    private String generateSignature(Map<String, String> params, String apiKey) throws Exception {
//        // 实现微信支付签名算法
//        return MiniWxPayUtil.generateSignature(params, apiKey);
//    }
    /**
     * 统一的签名验证方法
     */
    private boolean verifySignature(Map<String, String> dataMap) throws Exception {
        // 1. 获取签名
        String sign = dataMap.get("sign");
        if (StringUtils.isEmpty(sign)) {
            log.error("签名参数缺失");
            return false;
        }

        // 2. 创建有序Map（按ASCII码排序）
        Map<String, String> signMap = new TreeMap<>(dataMap);
        signMap.remove("sign"); // 移除签名本身

        // 3. 生成待签名字符串
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : signMap.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        sb.append("key=").append(wxPayConfig.getApiKey());
        String stringSignTemp = sb.toString();

        // 4. 计算签名
        String calculatedSign = DigestUtils.md5Hex(stringSignTemp).toUpperCase();

        // 5. 验证签名
        boolean isValid = sign.equals(calculatedSign);
        if (!isValid) {
            log.error("签名验证失败! 接收签名: {}, 计算签名: {}", sign, calculatedSign);
            log.error("待签名字符串: {}", stringSignTemp);
        }
        return isValid;
    }
    /**
     * 生成微信支付签名（统一使用TreeMap保证参数顺序）
     */
    private String generateSignature(Map<String, String> params, String apiKey) throws Exception {
        // 1. 参数排序
        Map<String, String> sortedParams = new TreeMap<>(params);

        // 2. 拼接键值对
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }

        // 3. 拼接API密钥
        sb.append("key=").append(apiKey);

        // 4. MD5加密并转为大写，处理用户保存对密码加密
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();
    }













//    private void saveRefundRecord(WechatOrder order, String outRefundNo, Map<String, String> result) {
//        RefundRecord record = new RefundRecord();
//        record.setOrderId(order.getId());
//        record.setWechatOrderId(order.getOrderId());
//        record.setRefundOutTradeNo(outRefundNo);
//        record.setRefundId(result.get("refund_id"));
//        record.setRefundFee(order.getRefundFee());
//        record.setTotalFee(order.getTotalFee());
//        record.setRefundStatus("处理中");
//        record.setCreateTime(new Date());
//
//        refundRecordMapper.insert(record);
//    }

    // 辅助方法
    private String generateRefundNo(String merId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timestamp = sdf.format(new Date());
        Random random = new Random();
        int randomNum = random.nextInt(1000);
        return "RF" + merId + timestamp + String.format("%03d", randomNum);
    }

    private String generateNonceStr() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 32);
    }



    private String mapToXml(Map<String, String> map) {
        // 实现 Map 到 XML 的转换
        return MiniWxPayUtil.mapToXml(map);
    }

}